package org.asiainfo.file.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.asiainfo.common.core.enums.UploadType;
import org.asiainfo.common.core.utils.MapstructUtils;
import org.asiainfo.common.core.utils.SpringUtils;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.core.utils.file.FileUploadUtils;
import org.asiainfo.common.core.utils.file.FileUtils;
import org.asiainfo.file.config.properties.FtpProperties;
import org.asiainfo.file.domain.AttactmentInfo;
import org.asiainfo.file.domain.bo.AttactmentInfoBo;
import org.asiainfo.file.domain.vo.AttactmentInfoVo;
import org.asiainfo.file.mapper.AttactmentInfoMapper;
import org.asiainfo.file.service.AttactmentInfoService;
import org.asiainfo.file.service.FileStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * ftp 附件策略
 *
 * @author dotor-ww
 */
@Service("ftp" + FileStrategy.BASE_NAME)
@Slf4j
public class FtpFileStrategy implements FileStrategy {

    @Autowired
    private FtpProperties ftpProperties;

    @Autowired(required = false)
    private FTPClient ftpClient;

    @Autowired
    private AttactmentInfoMapper attactmentInfoMapper;

    /**
     * 上传附件
     *
     * @param attactmentInfoBo 附件信息
     * @param file             文件
     * @return 上传结果
     */
    @Override
    public AttactmentInfoVo uploadFile(AttactmentInfoBo attactmentInfoBo, MultipartFile file) throws Exception {
        String fileName = FileUploadUtils.extractFilename(file);
        String filePath = ftpProperties.getBasePath();
        String fileUrl = filePath + "/" + fileName;
        File toFile = FileUtils.multipartFileToFile(file);
        uploadFileToFtp(toFile, fileName, filePath);
        AttactmentInfo attactmentInfo = SpringUtils.getBean(AttactmentInfoService.class)
            .buildAttactmentInfo(attactmentInfoBo.getAttactId(), fileUrl, file);
        attactmentInfo.setUploadType(UploadType.FTP.getCode());
        attactmentInfo.setFileName(file.getOriginalFilename());
        attactmentInfoMapper.insertSelective(attactmentInfo);
        return MapstructUtils.convert(attactmentInfo, AttactmentInfoVo.class);
    }

    /**
     * 上传文件到ftp
     *
     * @param file     文件
     * @param fileName 文件名
     * @param filePath 文件路径
     */
    private void uploadFileToFtp(File file, String fileName, String filePath) throws Exception {
        int replyCode = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(replyCode)) {
            // 设置文件传输模式为二进制，可以保证传输的内容不会被改变
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            // 注：上传文件都为0字节，设置为被动模式即可
            ftpClient.enterLocalPassiveMode();
            // 跳转到指定路径，逐级跳转，不存在的话就创建再进入
            toPathOrCreateDir(filePath);
            try (InputStream inputStream = new FileInputStream(file)) {
                // 上传文件
                ftpClient.storeFile(fileName, inputStream);
            }
        }
    }

    /**
     * 跳转到指定路径，逐级跳转，不存在的话就创建再进入
     *
     * @param filePath 文件路径
     * @throws IOException 报错信息
     */
    private void toPathOrCreateDir(String filePath) throws IOException {
        String[] dirs = filePath.split("/");
        String currentWorkingDirectory = ftpClient.printWorkingDirectory(); // 缓存当前工作目录
        boolean isRootDir = true;
        for (String dir : dirs) {
            if (StringUtils.isBlank(dir)) {
                continue;
            }
            if (isRootDir) {
                isRootDir = false;
                ftpClient.changeWorkingDirectory("/"); // 进入根目录
            }
            if (!ftpClient.changeWorkingDirectory(dir)) {
                ftpClient.makeDirectory(dir);
                ftpClient.changeWorkingDirectory(dir);
            }
        }
        // 恢复之前的工作目录
        ftpClient.changeWorkingDirectory(currentWorkingDirectory);
    }
}
